package org.mebusw.davincicode;

import org.mebusw.davincicode.vo.DavinciCard;
import org.mebusw.davincicode.vo.DavinciPlayer;
import org.mebusw.vo.Player;

/**
 * @author j1shen
 * @see DavinciCard
 */
public class PlayerManager {
	private DavinciPlayer player;

	public PlayerManager() {
	}

	public PlayerManager(Player player) {
		this.player = (DavinciPlayer) player;
	}

	/**
	 * Insert a card into specific position.
	 * 
	 * @param card
	 *            the card to be inserted
	 * @param pos
	 *            the position to insert to
	 */
	public void insert(DavinciCard card, int pos) {
		player.getHand().add(pos, card);
	}

	/**
	 * Automatically insert a card with sorting.
	 * 
	 * @param card
	 *            the card to be inserted
	 */
	public void insertSort(DavinciCard card) {
		for (int i = 0; i < player.getHand().size() + 1; i++) {
			if (validatePos(card, i)) {
				insert(card, i);
				break;
			}
		}
	}

	/**
	 * Insert a card to the last position without sorting.
	 * 
	 * @param card
	 */
	public void insertLast(DavinciCard card) {
		player.getHand().add(player.getHand().size(), card);
	}

	/**
	 * Get the card in the last position.
	 * 
	 * @return The last card or null
	 */
	public DavinciCard getLast() {
		if (player.getHand().size() > 0)
			return (DavinciCard) player.getHand().get(
					player.getHand().size() - 1);
		else
			return null;
	}

	/**
	 * Validate whether a card can be insert into specific position. <br>
	 * <br>
	 * All cards should be sorted by ascending order, Black less than White if
	 * the same number, joker can be in any place.
	 * 
	 * @param card
	 *            the card to be inserted
	 * @param pos
	 *            the position to insert to
	 * @return true if the insertion is valid (but the card would not be
	 *         inserted)
	 */
	public boolean validatePos(DavinciCard card, int pos) {
		DavinciCard prev, succ;
		boolean result = false;

		if (pos < 0 || pos > player.getHand().size())
			return false;

		try {
			prev = (DavinciCard) player.getHand().get(pos - 1);
			if (prev.isJoker()) { // skip one joker
				prev = (DavinciCard) player.getHand().get(pos - 2);
				if (prev.isJoker()) // skip another joker
					prev = (DavinciCard) player.getHand().get(pos - 3);
			}
			if (card.getValue() == prev.getValue() && (prev.isBlack())
					|| card.getValue() > prev.getValue())
				result = true;
		} catch (IndexOutOfBoundsException e) {
			// reach to the head (after skipping any jokers)
			result = true;
		}

		try {
			succ = (DavinciCard) player.getHand().get(pos + 0);
			if (succ.isJoker()) { // skip one joker
				succ = (DavinciCard) player.getHand().get(pos + 1);
				if (succ.isJoker()) // skip another joker
					succ = (DavinciCard) player.getHand().get(pos + 2);
			}
			if (card.getValue() == succ.getValue() && !(succ.isBlack())
					|| card.getValue() < succ.getValue())
				result &= true;
			else
				result = false;
		} catch (IndexOutOfBoundsException e) {
			// reach to the tail (after skipping any jokers)
			result &= true;
		}

		return result;

	}

	public void reinsertSortLast() {
		DavinciCard card = getLast();
		player.getHand().remove(player.getHand().size() - 1);
		insertSort(card);

	}

	public void reinsertJokerLast(int newPos) {
		DavinciCard card = getLast();
		player.getHand().remove(player.getHand().size() - 1);
		insert(card, newPos);

	}

	public int getStandingCardCount() {
		DavinciCard card;
		int sum = 0;
		for (int i = 0; i < player.getHand().size(); i++) {
			card = (DavinciCard) player.getHand().get(i);
			if (!card.isRevealed())
				sum++;
		}
		return sum;
	}

	public void setPlayer(DavinciPlayer player) {
		this.player = player;
	}

	public DavinciPlayer getPlayer() {
		return player;
	}

	public int getHandSize() {
		return player.getHand().size();
	}

	public DavinciCard getCard(int index) {
		return (DavinciCard) player.getHand().get(index);
	}
}
